<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Begin Jekyll SEO tag v2.7.1 -->
<title>AOF | 微光</title>
<meta name="generator" content="Jekyll v4.2.1">
<meta property="og:title" content="AOF">
<meta property="og:locale" content="en_US">
<meta name="description" content="AOF">
<meta property="og:description" content="AOF">
<link rel="canonical" href="/redis/persist/aof.html">
<meta property="og:url" content="/redis/persist/aof.html">
<meta property="og:site_name" content="微光">
<meta property="og:type" content="article">
<meta property="article:published_time" content="2022-01-13T00:00:00+08:00">
<meta name="twitter:card" content="summary">
<meta property="twitter:title" content="AOF">
<script type="application/ld+json">
{"description":"AOF","url":"/redis/persist/aof.html","headline":"AOF","dateModified":"2022-01-13T00:00:00+08:00","datePublished":"2022-01-13T00:00:00+08:00","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"/redis/persist/aof.html"},"@context":"https://schema.org"}</script>
<!-- End Jekyll SEO tag -->
<link rel="stylesheet" href="/assets/css/normalize.css">
  <link rel="stylesheet" href="/assets/css/style.css">
<link type="application/atom+xml" rel="alternate" href="/feed.xml" title="微光">
</head>
<body>
<header class="site-header">

  <div class="wrapper">
<a class="site-title" rel="author" href="/">微光</a><nav class="site-nav">
        <input type="checkbox" id="nav-trigger" class="nav-trigger">
        <label for="nav-trigger">
          <span class="menu-icon">
            <svg viewbox="0 0 18 15" width="18px" height="15px">
              <path d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.032C17.335,0,18,0.665,18,1.484L18,1.484z M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.032C17.335,6.031,18,6.696,18,7.516L18,7.516z M18,13.516C18,14.335,17.335,15,16.516,15H1.484 C0.665,15,0,14.335,0,13.516l0,0c0-0.82,0.665-1.483,1.484-1.483h15.032C17.335,12.031,18,12.695,18,13.516L18,13.516z"></path>
            </svg>
          </span>
        </label>

        <div class="trigger">
<a class="page-link" href="/about/">About</a><a class="page-link" href="/doc/main">DocMain</a><a class="page-link" href="/sites.html">Sites</a>
</div>
      </nav>
</div>
</header>
<div class="x-collections-bar">
  <a href="/">Home</a>
  
    
      <a href="/algri/index">算法</a>
    
  
    
      <a href="/java/index">Java</a>
    
  
    
  
    
  
    
      <a href="/redis/index">Redis</a>
    
  
</div>

<div class="x-content-side-layout x-container">
  <div class="x-left">
    <h3>本文目录</h3>
    <ul id="toc" class="section-nav">
<li class="toc-entry toc-h2"><a href="#aof">AOF</a></li>
<li class="toc-entry toc-h2"><a href="#aof-%E6%BC%94%E7%A4%BA">AOF 演示</a></li>
<li class="toc-entry toc-h2"><a href="#aof-%E9%87%8D%E5%86%99">AOF 重写</a></li>
<li class="toc-entry toc-h2">
<a href="#aof-%E6%8C%81%E4%B9%85%E6%80%A7">AOF 持久性</a>
<ul>
<li class="toc-entry toc-h3"><a href="#appendfsync-no">appendfsync no</a></li>
<li class="toc-entry toc-h3"><a href="#appendfsync-everysec">appendfsync everysec</a></li>
<li class="toc-entry toc-h3"><a href="#appendfsync-always">appendfsync always</a></li>
</ul>
</li>
<li class="toc-entry toc-h2"><a href="#%E4%B8%BA%E4%BD%95-pipeline-%E5%B0%B1%E4%B8%8D%E5%90%8C%E4%BA%86">为何 Pipeline 就不同了？</a></li>
<li class="toc-entry toc-h2"><a href="#aof-%E4%B8%8E%E4%BA%8B%E5%8A%A1">AOF 与事务</a></li>
<li class="toc-entry toc-h2"><a href="#%E4%B8%8E-postgresql-%E6%AF%94%E8%BE%83">与 PostgreSQL 比较</a></li>
<li class="toc-entry toc-h2"><a href="#%E5%8F%82%E8%80%83">参考</a></li>
<li class="toc-entry toc-h2"><a href="#%E6%89%A9%E5%B1%95%E9%98%85%E8%AF%BB">扩展阅读</a></li>
</ul>
  </div>
  <div class="x-content">
    <h1><strong>Redis - AOF</strong></h1>
    <small>2022-01-13 00:00:00 +0800</small>
    
    <article class="x-article"><h2 id="aof">
<a class="anchor" href="#aof" aria-hidden="true"><span class="octicon octicon-link"></span></a>AOF</h2>

<p><strong>仅追加文件</strong>（<em>Append Only File</em>）通常被简称为 AOF，是另一种主要的 Redis 持久化选择。它的工作方式极为简单：每当一个写操作修改了内存中的数据集后，这个操作就会被追加到日志末尾。这个生成的日志格式，和客户端与 Redis 通信时使用的数据格式相同，所以 AOF 甚至可以通过 netcat 管道传输到另一个实例中，或者在需要时很容易的解析。在重启时，Redis 重放这些操作来重建数据集。</p>

<p>AOF 的思想很简单，但是实际上要考虑的东西比 RDB 更复杂一点点点点。</p>

<h2 id="aof-演示">
<a class="anchor" href="#aof-%E6%BC%94%E7%A4%BA" aria-hidden="true"><span class="octicon octicon-link"></span></a>AOF 演示</h2>

<p>为展示 AOF 是如何工作的，我们做一个简单的实验，创建一个 Redis 2.6（或者更高版本）实例并打开 AOF 支持：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="go">./redis-server --appendonly yes
</span></code></pre></div></div>

<p>现在我们往这个实例发送一些写操作：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">redis 127.0.0.1:6379&gt;</span><span class="w"> </span><span class="nb">set </span>key1 Hello
<span class="go">OK
</span><span class="gp">redis 127.0.0.1:6379&gt;</span><span class="w"> </span>append key1 <span class="s2">" World!"</span>
<span class="go">(integer) 12
</span><span class="gp">redis 127.0.0.1:6379&gt;</span><span class="w"> </span>del key1
<span class="go">(integer) 1
</span><span class="gp">redis 127.0.0.1:6379&gt;</span><span class="w"> </span>del non_existing_key
<span class="go">(integer) 0
</span></code></pre></div></div>

<p>前三个操作会实际上修改数据集，第四个则不会，因为不存在名为 <code class="language-plaintext highlighter-rouge">non_existing_key</code> 的 key。下面是 AOF 的样子：</p>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">cat </span>appendonly.aof
<span class="go">*2
</span><span class="gp">$</span>6
<span class="go">SELECT
</span><span class="gp">$</span>1
<span class="go">0
*3
</span><span class="gp">$</span>3
<span class="go">set
</span><span class="gp">$</span>4
<span class="go">key1
</span><span class="gp">$</span>5
<span class="go">Hello
*3
</span><span class="gp">$</span>6
<span class="go">append
</span><span class="gp">$</span>4
<span class="go">key1
</span><span class="gp">$</span>7
<span class="go"> World!
*2
</span><span class="gp">$</span>3
<span class="go">del
</span><span class="gp">$</span>4
<span class="go">key1
</span></code></pre></div></div>

<p>如你所见，最后一个 <code class="language-plaintext highlighter-rouge">DEL</code> 命令并不存在，因为它没有对数据集产生任何修改。</p>

<p>新的命令只有对数据集产生影响时，才会被记录到 AOF 中，就这么简单。不过，不是所有的命令被记录时都和接收到的一模一样。比如对 list 的阻塞操作仅记录它最终产生的影响，就像一个普通的非阻塞命令那样。类似于 <code class="language-plaintext highlighter-rouge">INCRBYFLOAT</code> 的命令被记录为 <code class="language-plaintext highlighter-rouge">SET</code>，使用增加后的值作为 <code class="language-plaintext highlighter-rouge">SET</code> 进去的最终值，所以在重新加载 AOF 后，在不同的架构下不同的处理浮点数的方式不会导致不同的结果。</p>

<p>现在我们知道了 AOF 只做仅追加操作，所以不会导致数据崩溃，不过这个特性也会导致一个问题：上例中在 <code class="language-plaintext highlighter-rouge">DEL</code> 操作之后，对应的数据已经完全不存在了，但是 AOF 中依然花费了一些空间来保存这个数据的操作。这样一来，AOF 就成了一个<em>不断变大</em>的文件。那么，在 AOF 变得很大时该怎么办呢？</p>

<h2 id="aof-重写">
<a class="anchor" href="#aof-%E9%87%8D%E5%86%99" aria-hidden="true"><span class="octicon octicon-link"></span></a>AOF 重写</h2>

<p>AOF 文件变得过大时，Redis 会从头开始把它写到一个临时文件中。重写数据不是从老的 AOF 中来，而是直接访问 Redis 内存，这样一来，Redis 就创建一个尽可能小的 AOF 文件，又可以避免在创建新 AOF 文件时从磁盘中读取老的数据。</p>

<p>一旦重写完成，临时文件就会被 fsync 到磁盘，并用于替换老的 AOF 文件。</p>

<p>你可能想知道，在重写的过程中，被写到 Redis 中的数据发生了什么。新数据会被简单地写到老的（当前的）AOF 文件中，同时会被入队到一个内存中的 buffer 里，这样一来，当新的 AOF 已经准好了，我们就可以把这些丢失的部分写进去，最后用新的 AOF 把旧的替换掉。</p>

<p>如你所见，所有的东西都是仅追加的，在重写 AOF 时，我们依然会把数据写到老的 AOF 中，因为创建新的 AOF 需要时间。这意味着在我们的分析中，我们可以简单避免考虑 AOF 被重写的情况。现在的问题是，多久进行一次 write(2) 和 多久进行一次 fsync(2)。</p>

<blockquote>
  <p>AOF 重写过程仅使用顺序的 I/O 操作，所以整个 dump 过程非常高效，甚至在旋转式磁盘（不支持随机 I/O）中也是如此。RDB 快照的生成也是如此。在数据库系统中，完全没有（对磁盘的）随机访问是一个很罕见的特性，主要是原因应该是 Redis 服务是从内存中读取数据，所以不需要对磁盘上的数据进行特殊的组织来适应随机访问的需求，仅在重启时会按顺序加载数据。</p>
</blockquote>

<h2 id="aof-持久性">
<a class="anchor" href="#aof-%E6%8C%81%E4%B9%85%E6%80%A7" aria-hidden="true"><span class="octicon octicon-link"></span></a>AOF 持久性</h2>

<p>在新命令执行时，Redis AOF 使用用户空间 buffer 来存储新数据。每当我们返回到时间循环中时，都会把 buffer 刷入磁盘，对 AOF 描述符使用一次 write(2) 系统调用，不过有三个不同的配置来精确控制 write(2) 的行为，尤其是 fsync(2) 调用。</p>

<p>这三个配置由 <strong>appendfsync</strong> 配置指令来控制，对应三个不同的值：<em>no</em>、<em>everysec</em>和<em>always</em>。这三个属性可以在运行时查询和修改，通过 <code class="language-plaintext highlighter-rouge">CONFIG</code> <code class="language-plaintext highlighter-rouge">SET</code> 命令，所以你可以在不停止 Redis 的情况下进行修改。</p>

<h3 id="appendfsync-no">
<a class="anchor" href="#appendfsync-no" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">appendfsync no</code>
</h3>

<p>在此配置下，Redis 完全不执行 fsync(2)。不过，这将确保客户端不使用 TODO: <a href="https://redis.io/topics/pipelining">流水线</a>，即，在发送下一个命令之前，等待接受当前命令回复的客户端，会收到一个当前命令执行成功的的确认消息，这个确认消息仅在改变被发送到内核后确认，方式是通过 write(2) 系统调用把命令写到 AOF 文件描述符中。</p>

<p>因为这个配置会使 Redis 不调用 fsync(2)，所以数据什么时候被提交到硬盘完全由内核决定，在大多数 Linux 系统中是每 30s 一次。</p>

<h3 id="appendfsync-everysec">
<a class="anchor" href="#appendfsync-everysec" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">appendfsync everysec</code>
</h3>

<p>在此配置下，数据被写到文件时，既会使用 write(2)，同时每秒还会调用一次 fsync(2) 把数据从内核刷到硬盘中。每当我们从事件循环中返回时，通常 write(2) 都会被执行，但并不保证总是。</p>

<p>不过，如果硬盘不能处理写速度，且后台的 fsync(2) 花费时间超过了 1 秒，Redis 就会把写时间延迟 1 秒，以避免写操作阻塞主线程，因为后台线程中执行的 fsync(2）使用同一个文件描述符。如果过了 2 秒 fsync(2) 都没有终止，Redis 最终会执行 write(2) （可能会阻塞）不计代价把数据传输到硬盘上。</p>

<p>所以在这种模式下，Redis 保证在最坏的情况下，2 秒钟内你写入的所有数据都会被提交到操作系统 buffer 中，并被传输到硬盘上。平均的情况是数据每秒提交一次。</p>

<h3 id="appendfsync-always">
<a class="anchor" href="#appendfsync-always" aria-hidden="true"><span class="octicon octicon-link"></span></a><code class="language-plaintext highlighter-rouge">appendfsync always</code>
</h3>

<p>在此模式下，如果客户端不使用 pipeline 却在发起新命令时等待命令返回，那么在确认被返回给客户端之前，数据会被同时写到文件和同步到磁盘（用 fsync(2)）。</p>

<p>这是我们能够得到的最高持久化级别，但是也比其他模式更慢。</p>

<p>Redis 默认的配置是 <code class="language-plaintext highlighter-rouge">appendfsync everysec</code>，这在速度（几乎和 <code class="language-plaintext highlighter-rouge">appendfsync no</code> 一样快）和持久化之间提供了一个很好的平衡。</p>

<blockquote>
  <p>Redis 实现的 <code class="language-plaintext highlighter-rouge">appendfsync always</code> 通常被成功<strong>合并提交</strong>(<em>group commit</em>，合并为一组一起提交）。这意味着，Redis 不是在每个写命令执行完后都使用 fsync(2)，Redis 能够在向一组客户端发送请求之前，在最后一个事件循环执行期间，把一组操作合并成一个 write+fsync 操作来提交。</p>

  <p>在实践中，这意味着如果你有几百个客户端同时执行写操作时，fsync(2) 会被分解，这样一来，即使旋转磁盘只能每秒支持 100-200 个操作时，那么在此模式下，Redis 也能够每秒支持数千个并发事务。</p>

  <p>这个特性在传统数据库中通常很难实现，不过 Redis 使这个东西变得非常简单。</p>
</blockquote>

<h2 id="为何-pipeline-就不同了">
<a class="anchor" href="#%E4%B8%BA%E4%BD%95-pipeline-%E5%B0%B1%E4%B8%8D%E5%90%8C%E4%BA%86" aria-hidden="true"><span class="octicon octicon-link"></span></a>为何 Pipeline 就不同了？</h2>

<p>用不同方式处理客户端发起的 pipelining，是因为客户端使用 pipelining 时为了提升写的速度，而牺牲了在执行下一个命令之前读取给定命令的能力。在回复客户端之前，没有提交点，而客户端在发送完命令之前也并不关心回复，而是追求速度。不过即使客户端正在使用 pipelining，write 和 fsync 系统调用（依赖于配置）也依然会在发布会到时间循环之前发生。</p>

<h2 id="aof-与事务">
<a class="anchor" href="#aof-%E4%B8%8E%E4%BA%8B%E5%8A%A1" aria-hidden="true"><span class="octicon octicon-link"></span></a>AOF 与事务</h2>

<p>AOF 保证 MULTI/EXEC 正确的事务语义，并在在文件末尾有一个损坏的事务时，会拒绝重新加载它。Redis 服务器中有一个工具可以移除 AOF 文件末尾的部分事务。</p>

<p>注意：因为 AOF 在每个时间循环遍历结束后，使用一个单一的 write(2) 系统调用来追加文件，所以不完整的事务仅可能出现在 Redis 写时发现磁盘却满了这种情况下。</p>

<h2 id="与-postgresql-比较">
<a class="anchor" href="#%E4%B8%8E-postgresql-%E6%AF%94%E8%BE%83" aria-hidden="true"><span class="octicon octicon-link"></span></a>与 PostgreSQL 比较</h2>

<p>所以，在默认配置下使用 AOF 持久化引擎时，Redis 的持久性到底怎样呢？</p>

<ul>
  <li>最糟糕的情况：它保证 write(2) 和 fsync(2) 在 2 秒钟内完成。</li>
  <li>一般情况：它在回复客户端之前先执行 write(2)，并且每秒执行一次 fsync(2)。</li>
</ul>

<p>有趣的是，在此情况下，Redis 依旧超快，有一些原因。其一是 fsync 是在后台线程中执行的，其他原因是 Redis 在写文件时是在一种仅追加的模式下，这是一个巨大优势。</p>

<p>不过，如果你需要最大化数据安全，且你的写负载不高，你就可以使用在任何数据库系统中都一样好的持久化方式：总是 <code class="language-plaintext highlighter-rouge">fsync</code>。</p>

<p>我们来一起读一下 PostgreSQL 的文档（注意，我们仅引用有趣的部分，你可以再这里找到<a href="read://https_www.postgresql.org/?url=https%3A%2F%2Fwww.postgresql.org%2Fdocs%2F9.1%2Fruntime-config-wal.html%23GUC-SYNCHRONOUS-COMMIT">完整的文档</a>）:</p>

<blockquote>
  <p><strong>fsync(boolean)</strong></p>

  <p>如果这个参数被打开，PostgreSQL 服务器会尝试确保更新被物理地写到了硬盘上，通过提交 fsync(2) 系统调用或者其他等价的方法（见 wal_sync_method）。这确保数据库集群<strong>在操作系统或者硬件崩掉后可以恢复到一个一致性的状态</strong>。</p>

  <p>[snip]</p>

  <p>在很多情况下，为非关键事务关掉 synchronous_commit 可以提供关闭fsync的许多潜在性能好处，而不会有伴随而来的数据损坏风险。</p>
</blockquote>

<p>所以 PostgreSQL 需要 fsync 数据来避免崩溃。幸运的是有了 Redis AOF，我们再也不用担心这个问题了，不可能有数据损坏。所以，我们来考察一下下一个参数，它和 Redis 的 fsync 策略相比非常接近，甚至可以说只有名字不同：</p>

<blockquote>
  <p><strong>synchronous_commit (enum)</strong></p>

  <p>指定事务提交返回 “success” 给客户端之前，是否会等到 WAL 记录被写到硬盘上。有效的值有 on、local 和 off。默认的也是安全的值是 on。当 off 时，在返回给客户端成功时和事务确实保证被安全写到硬盘上时之间，会有一段延迟。最大延迟是三倍的 wal_writer_delay。和 fsync 不同，设置此参数为 off 不会导致任何的数据库不一致：操作系统或者数据库崩溃导致一些最近宣称已提交的事务丢失，但是数据库状态会像那些个丢失的事务被干净的中断了一样。</p>
</blockquote>

<p>这时，我们就有了一些类似方式来调优 Redis 了。基本上，PostgreSQL 用户会告诉你，想要速度么？禁用同步提交可能是一个好主意。Redis 中也类似：追求速度么？不要使用 <code class="language-plaintext highlighter-rouge">appendfsync always</code>。</p>

<p>现在，如果你禁用了 PostgreSQL 中的同步提交，你就处在了一种和 Redis <code class="language-plaintext highlighter-rouge">appendfsync everysec</code> 类似的情况里了，因为 wal_writer_delay 默认是 200 毫秒，同时文档描述，你需要把这个时间乘以 3 来得到实际的写延迟，即 600 毫秒，非常接近于 Redis 默认的 1 秒了。</p>

<blockquote>
  <p>MySQL InnoDB 有一个类似的参数用户用户调优。文档中是这样的：</p>

  <p>如果 <code class="language-plaintext highlighter-rouge">innodb_flush_log_at_trx_commit</code> 的值是 0，那么日志 buffer 每秒被写到日志文件一次，并在日志文件上执行一次 flush 到硬盘的操作，不过在日志提交时什么都不做。当值是 1 时（默认），在每个事务提交时就把日志 buffer 往日志文件写一次，并在日志文件上执行一次 flush 到硬盘的操作。当值是 2 时，日志 buffer 在每次提交时把日志 buffer 写到文件中，但是不会字文件上执行 flush 到硬盘的操作。不过，日志文件的 flush 操作在值是 2 时每秒钟执行一次。注意，每秒一次 flush 也不是 100% 保证发送的，因为进程调度的原因。</p>

  <p>你可以<a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit">此读到更多信息</a>。</p>
</blockquote>

<p>长话短说：即使 Redis 是一个内存数据库，不过和其他硬盘数据库相比，它依然提供了很好的持久性保证。</p>

<p>从更务实的角度看，Redis 提供的 AOF 和 RDB 快照可以同时打开（这是建议的设置），同时提供了操作的便利性和数据持久性。</p>

<p>我们说的所有有关 Redis 持久性的东西，只要要求把数据持久化到硬盘时，不仅适用于 Redis 用作数据库时，也适用于用 Redis 实现的队列，这些场景都能提供很好的持久性保证。</p>

<p>TODO: 太长了，剪短</p>

<h2 id="参考">
<a class="anchor" href="#%E5%8F%82%E8%80%83" aria-hidden="true"><span class="octicon octicon-link"></span></a>参考</h2>

<ul>
  <li><a href="http://oldblog.antirez.com/post/redis-persistence-demystified.html">Redis persistence demystified</a></li>
</ul>

<h2 id="扩展阅读">
<a class="anchor" href="#%E6%89%A9%E5%B1%95%E9%98%85%E8%AF%BB" aria-hidden="true"><span class="octicon octicon-link"></span></a>扩展阅读</h2>

<ul>
  <li><a href="https://sqlite.org/atomiccommit.html">Atomic Commit In SQLite</a></li>
  <li><a href="https://queue.acm.org/detail.cfm?id=2367378">Disk lie</a></li>
  <li><a href="https://www.slideshare.net/iammutex/what-every-data-programmer-needs-to-know-about-disks">what-every-data-programmer-needs-to-know-about-disk</a></li>
</ul>
</article>
  </div>
  <div class="x-right">
    <h3>Redis</h3>
    
      <div class="x-collection-section">
        <h4>开始</h4>
        
        <ol>
          
            
              <li><a href="/redis/index.html">开始</a></li>
            
          
            
              <li><a href="/redis/install.html">安装</a></li>
            
          
            
              <li><a href="/redis/concept.html">相关概念预览</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>数据类型</h4>
        
        <ol>
          
            
              <li><a href="/redis/data-type/key-and-string.html">Key 和 String</a></li>
            
          
            
              <li><a href="/redis/data-type/list.html">List</a></li>
            
          
            
              <li><a href="/redis/data-type/hash.html">Hash</a></li>
            
          
            
              <li><a href="/redis/data-type/set.html">Set</a></li>
            
          
            
              <li><a href="/redis/data-type/zset.html">Sorted Set</a></li>
            
          
            
              <li><a href="/redis/data-type/bitmap.html">Bitmap</a></li>
            
          
            
              <li><a href="/redis/data-type/hyperloglog.html">Hyperloglog</a></li>
            
          
            
              <li><a href="/redis/data-type/geo.html">Geo</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>其他特性</h4>
        
        <ol>
          
            
              <li><a href="/redis/feature/pipeline.html">流水线处理</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>持久化</h4>
        
        <ol>
          
            
              <li><a href="/redis/persist/durability.html">持久化在说什么</a></li>
            
          
            
              <li><a href="/redis/persist/rdb.html">快照（Snapshotting）</a></li>
            
          
            
              <li class="active"><a href="/redis/persist/aof.html">AOF</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>运维</h4>
        
        <ol>
          
            
              <li><a href="/redis/ops/persistence.html">持久化方案</a></li>
            
          
        </ol>
      </div>
    
      <div class="x-collection-section">
        <h4>应用场景</h4>
        
        <ol>
          
            
              <li><a href="/redis/usecase/blogs.html">应用场景相关文章</a></li>
            
          
        </ol>
      </div>
    
  </div>
</div>
<footer class="site-footer h-card">
  <data class="u-url" href="/"></data>

  <div class="wrapper">

    <div class="footer-col-wrapper">
      <div class="footer-col">
        <p class="feed-subscribe">
          <a href="/feed.xml">
            <svg class="svg-icon orange">
              <use xlink:href="/assets/social-icons.svg#rss"></use>
            </svg><span>Subscribe</span>
          </a>
        </p>
      </div>
      <div class="footer-col">
        <p>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</p>
      </div>
    </div>

    <div class="social-links"></div>

  </div>

</footer>
</body>
</html>
